package com.lyeducation.services.base;

import com.lyeducation.core.base.AntiInjectionInterface;
import com.lyeducation.util.ReflectUtil;
import com.lyeducation.util.Reflections;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;

@Component
public class AntiInjectionInterfaceImpl implements AntiInjectionInterface {
  @Override
  public boolean checkSqlAntiInfusion(Set<String> selSqlTabColumns, Class<?>... entityClazzs) {
    boolean res = true;
    for (Class<?> clazz : entityClazzs) {
      checkAntiInjectionByOneEntity(selSqlTabColumns, clazz);
    }
    if (selSqlTabColumns.size() == 0) {
      res = false;
    }
    return res;
  }

  /**
   * 防sql注入
   *
   * @param selSqlTabColumns sql语句的条件key 执行完此方法后sqlColums便是注入的字段 如果sqlColums集合长度size为0则说明没用注入key
   * @param entityClazz 当前校验的表实体
   * @return 返回未被校验的字段集 当集合size为0时则说明 该sql语句所有需要被查询的表列selSqlTabColumns未被注入
   */
  public void checkAntiInjectionByOneEntity(Set<String> selSqlTabColumns, Class<?> entityClazz) {
    if (selSqlTabColumns.size() == 0) {
      return;
    }
    Field[] fields = entityClazz.getDeclaredFields();
    Set<String> needDelSelSqlTabColumns = new HashSet<>();
    for (Field field : fields) {
      Reflections.makeAccessible(field);
      String sourceClassType = field.getType().toString();
      int lastIndex = sourceClassType.lastIndexOf(".");
      String classType = sourceClassType.substring(lastIndex + 1);
      if (classType.contains("List") || classType.contains("Set") || classType.contains("Map")) {
          continue;
      }
      // 如果是非集合引用类型则需要校验该成员引用类型其下的字段
      if (!ReflectUtil.isBaseDataType(classType)) {
        try {
          String[] package_class = sourceClassType.split("\\s+");
          Class<?> properPojoClass = Class.forName(package_class[1]);
          checkAntiInjectionByOneEntity(selSqlTabColumns, properPojoClass);
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        }
      }
      String fileName = field.getName();
      for (String needCheckSqlTableColum : selSqlTabColumns) {
        if (fileName.equals(needCheckSqlTableColum)) {
          needDelSelSqlTabColumns.add(fileName);
        }
      }
    }
    if (needDelSelSqlTabColumns.size() > 0) {
        selSqlTabColumns.removeAll(needDelSelSqlTabColumns);
    }
    if (entityClazz.getSuperclass().equals(Object.class)) {
        return;
    }

    checkAntiInjectionByOneEntity(selSqlTabColumns, entityClazz.getSuperclass());
  }
}
